#include "wm_include.h"
#include "lcd.h"
#include "wm_gpio_afsel.h"
#include "lcd_spi_driver.h"
#include "string.h"
//液晶IO初始化配置
void LCD_GpioInit(void)
{
	int clk = 20000000;   // 2 M
	int type = 2;         // 2 DMA
	/*MASTER SPI configuratioin*/
	wm_spi_cs_config(LCD_CS);
	wm_spi_ck_config(LCD_SCL);
	wm_spi_do_config(LCD_SDA);

	tls_gpio_cfg(WM_IO_PB_26, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
	tls_gpio_write(WM_IO_PB_26,FALSE);

	tls_gpio_cfg(LCD_BL, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
	tls_gpio_cfg(LCD_DC,  WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
	tls_gpio_cfg(LCD_RST, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
	tls_spi_trans_type(type);
    tls_spi_setup(TLS_SPI_MODE_3, TLS_SPI_CS_LOW, clk);
}

void LCD_Reset(void)
{
	LCD_RST_CLR;
	tls_os_time_delay(50);
	LCD_RST_SET;
	tls_os_time_delay(25);
}

void LCD_Back_On(void)
{
	LCD_LED_SET;
}

void LCD_Back_Off(void)
{
	LCD_LED_CLR;
}

static void LCD_WriteReg(u8 reg)
{
	S_WriteReg(reg);
}

static void LCD_WriteData8(u8 data)
{
	S_WriteData8(data);
}

static void LCD_WriteData16(u16 data)
{
	S_WriteData16(data);
}

static void LCD_WriteData(u8 *data, u32 len)
{
	u32 t1 = 0, t2 = 0;
	
	t1 = tls_os_get_time();
	S_WriteData(data, len);
	t2 = tls_os_get_time();
	printf("s %d use %d\n", len, t2 - t1);

}

void LCD_Init(void)
{
	LCD_GpioInit();
	LCD_Reset();
	LCD_Back_On();

	//LCD Init For 1.44Inch LCD Panel with ST7735R.
	LCD_WriteReg(0x11);//Sleep exit 
	tls_os_time_delay(60);

#if 1		
	//ST7735R Frame Rate
	LCD_WriteReg(0xB1); 
	LCD_WriteData8(0x01); 
	LCD_WriteData8(0x2C); 
	LCD_WriteData8(0x2D); 

	LCD_WriteReg(0xB2); 
	LCD_WriteData8(0x01); 
	LCD_WriteData8(0x2C); 
	LCD_WriteData8(0x2D); 

	LCD_WriteReg(0xB3); 
	LCD_WriteData8(0x01); 
	LCD_WriteData8(0x2C); 
	LCD_WriteData8(0x2D); 
	LCD_WriteData8(0x01); 
	LCD_WriteData8(0x2C); 
	LCD_WriteData8(0x2D); 
	
	LCD_WriteReg(0xB4); //Column inversion 
	LCD_WriteData8(0x07); 
	
	//ST7735R Power Sequence
	LCD_WriteReg(0xC0); 
	LCD_WriteData8(0xA2); 
	LCD_WriteData8(0x02); 
	LCD_WriteData8(0x84); 
	LCD_WriteReg(0xC1); 
	LCD_WriteData8(0xC5); 

	LCD_WriteReg(0xC2); 
	LCD_WriteData8(0x0A); 
	LCD_WriteData8(0x00); 

	LCD_WriteReg(0xC3); 
	LCD_WriteData8(0x8A); 
	LCD_WriteData8(0x2A); 
	LCD_WriteReg(0xC4); 
	LCD_WriteData8(0x8A); 
	LCD_WriteData8(0xEE); 
	
	LCD_WriteReg(0xC5); //VCOM 
	LCD_WriteData8(0x0E); 
	
	LCD_WriteReg(0x36); //MX, MY, RGB mode 
	LCD_WriteData8(0xC0); 
	
	//ST7735R Gamma Sequence
	LCD_WriteReg(0xe0); 
	LCD_WriteData8(0x0f); 
	LCD_WriteData8(0x1a); 
	LCD_WriteData8(0x0f); 
	LCD_WriteData8(0x18); 
	LCD_WriteData8(0x2f); 
	LCD_WriteData8(0x28); 
	LCD_WriteData8(0x20); 
	LCD_WriteData8(0x22); 
	LCD_WriteData8(0x1f); 
	LCD_WriteData8(0x1b); 
	LCD_WriteData8(0x23); 
	LCD_WriteData8(0x37); 
	LCD_WriteData8(0x00); 	
	LCD_WriteData8(0x07); 
	LCD_WriteData8(0x02); 
	LCD_WriteData8(0x10); 

	LCD_WriteReg(0xe1); 
	LCD_WriteData8(0x0f); 
	LCD_WriteData8(0x1b); 
	LCD_WriteData8(0x0f); 
	LCD_WriteData8(0x17); 
	LCD_WriteData8(0x33); 
	LCD_WriteData8(0x2c); 
	LCD_WriteData8(0x29); 
	LCD_WriteData8(0x2e); 
	LCD_WriteData8(0x30); 
	LCD_WriteData8(0x30); 
	LCD_WriteData8(0x39); 
	LCD_WriteData8(0x3f); 
	LCD_WriteData8(0x00); 
	LCD_WriteData8(0x07); 
	LCD_WriteData8(0x03); 
	LCD_WriteData8(0x10);  
	
	LCD_WriteReg(0x2a);
	LCD_WriteData8(0x00);
	LCD_WriteData8(0x00);
	LCD_WriteData8(0x00);
	LCD_WriteData8(0x7f);

	LCD_WriteReg(0x2b);
	LCD_WriteData8(0x00);
	LCD_WriteData8(0x00);
	LCD_WriteData8(0x00);
	LCD_WriteData8(0x9f);
	
	LCD_WriteReg(0xF0); //Enable test command  
	LCD_WriteData8(0x01); 
	LCD_WriteReg(0xF6); //Disable ram power save mode 
	LCD_WriteData8(0x00); 
	
	LCD_WriteReg(0x3A); //65k mode 
	LCD_WriteData8(0x05); 

	LCD_WriteReg(0x29);//Display on	 
#else
	//with ST7789
	LCD_WriteReg(0x36);	// left->right top->bottom
	LCD_WriteData8(0x00);
	
	LCD_WriteReg(0x3A);	// rgb565
	LCD_WriteData8(0x05);
	
	LCD_WriteReg(0xB2);
	LCD_WriteData8(0x0C);
	LCD_WriteData8(0x0C);
	LCD_WriteData8(0x00);
	LCD_WriteData8(0x33);
	LCD_WriteData8(0x33);
	
	LCD_WriteReg(0xB7);
	LCD_WriteData8(0x35);
	
	LCD_WriteReg(0xBB);
	LCD_WriteData8(0x19);
	
	LCD_WriteReg(0xC0);
	LCD_WriteData8(0x2C);
	
	LCD_WriteReg(0xC2);
	LCD_WriteData8(0x01);
	
	LCD_WriteReg(0xC3);
	LCD_WriteData8(0x12);
	
	LCD_WriteReg(0xC4);
	LCD_WriteData8(0x20);
	
	LCD_WriteReg(0xC6);
	LCD_WriteData8(0x0F);
	
	LCD_WriteReg(0xD0);
	LCD_WriteData8(0xA4);
	LCD_WriteData8(0xA1);
	
	LCD_WriteReg(0xE0);
	LCD_WriteData8(0xD0);
	LCD_WriteData8(0x04);
	LCD_WriteData8(0x0D);
	LCD_WriteData8(0x11);
	LCD_WriteData8(0x13);
	LCD_WriteData8(0x2B);
	LCD_WriteData8(0x3F);
	LCD_WriteData8(0x54);
	LCD_WriteData8(0x4C);
	LCD_WriteData8(0x18);
	LCD_WriteData8(0x0D);
	LCD_WriteData8(0x0B);
	LCD_WriteData8(0x1F);
	LCD_WriteData8(0x23);
	
	LCD_WriteReg(0xE1);
	LCD_WriteData8(0xD0);
	LCD_WriteData8(0x04);
	LCD_WriteData8(0x0C);
	LCD_WriteData8(0x11);
	LCD_WriteData8(0x13);
	LCD_WriteData8(0x2C);
	LCD_WriteData8(0x3F);
	LCD_WriteData8(0x44);
	LCD_WriteData8(0x51);
	LCD_WriteData8(0x2F);
	LCD_WriteData8(0x1F);
	LCD_WriteData8(0x1F);
	LCD_WriteData8(0x20);
	LCD_WriteData8(0x23);
	
	LCD_WriteReg(0x21);
	LCD_WriteReg(0x29);
#endif
}

void LCD_Address_Set(u16 x_start, u16 y_start, u16 x_end, u16 y_end)
{
#if 1
	LCD_WriteReg(0x2A);
	LCD_WriteData16(x_start+2);
	LCD_WriteData16(x_end+2);
	LCD_WriteReg(0x2B);
	LCD_WriteData16(y_start+1);
	LCD_WriteData16(y_end+1);
	LCD_WriteReg(0x2C);
#else
	LCD_WriteReg(0x2A);
	LCD_WriteData16(x_start);
	LCD_WriteData16(x_end);
	LCD_WriteReg(0x2B);
	LCD_WriteData16(y_start);
	LCD_WriteData16(y_end);
	LCD_WriteReg(0x2C);
#endif

}
// 整个屏幕填充颜色
void LCD_Clear(u16 Color)               
{		
	// LCD_Fill(0, 0, X_MAX_PIXEL, Y_MAX_PIXEL, Color);

	LCD_Address_Set(0,0,X_MAX_PIXEL-1,Y_MAX_PIXEL-1);
	LCD_WriteReg(0x2C);
	u32 total = X_MAX_PIXEL * Y_MAX_PIXEL * 2;
	u8 High_8bit = Color>>8;
	u8 Low_8bit = Color;
	u8 *data =  tls_mem_alloc(8160);

	if(data == NULL) {
		printf("mem null\n");
		return;
	}
	else {
		memset(data, Low_8bit, 8160);
		for(int i = 0; i<8160; i+=2)
		{
			data[i] = High_8bit;
		}
	}

	u16 body = total/8160;
	u16 tail = total%8160;
    if(body > 0)
	{
		do
		{
			S_WriteData((u8 *)data, 8160);
		} while (--body);
	}
	if(tail > 0)
	{
		S_WriteData((u8 *)data, tail);
	}
	tls_mem_free(data);
}
// 在指定区域田中颜色
void LCD_Fill(u16 x_start, u16 y_start, u16 x_end, u16 y_end, u16 color)
{
	u16 i, j;
	
	LCD_Address_Set(x_start, y_start, x_end - 1, y_end - 1);
	for (i = y_start; i < y_end; i++)
	{
		for (j = x_start; j < x_end; j++)
		{
			LCD_WriteData16(color);
		}
	}
}

// 画点
void LCD_DrawPoint(u16 x, u16 y, u16 color)
{
	LCD_Address_Set(x, y, x, y);
	LCD_WriteData16(color);
}

// 画线
void LCD_DrawLine(u16 x_start, u16 y_start, u16 x_end, u16 y_end, u16 color)
{
	u16 i;
	int x = 0, y = 0, dx, dy, offset;
	int stepx, stepy, nowx, nowy;
	
	dx = x_end - x_start;
	dy = y_end - y_start;
	
	nowx = x_start;
	nowy = y_start;
	
	stepx = (dx > 0) ? 1 : ((dx == 0) ? 0 : -1);
	stepy = (dy > 0) ? 1 : ((dy == 0) ? 0 : -1);
	dx = (stepx >= 0) ? dx : -dx;
	dy = (stepy >= 0) ? dy : -dy;
	offset = (dx > dy) ? dx : dy;
	
	for (i = 0; i < (offset + 1); i++)
	{
		LCD_DrawPoint(nowx, nowy, color);
		x += dx;
		y += dy;
		if (x > offset)
		{
			x -= offset;
			nowx += stepx;
		}
		if (y > offset)
		{
			y -= offset;
			nowy += stepy;
		}
	}
}

// 画矩形
void LCD_DrawRectangle(u16 x_start, u16 y_start, u16 x_end, u16 y_end, u16 color)
{
	LCD_DrawLine(x_start, y_start, x_end, y_start, color);
	LCD_DrawLine(x_end, y_start, x_end, y_end, color);
	LCD_DrawLine(x_end, y_end, x_start, y_end, color);
	LCD_DrawLine(x_start, y_end, x_start, y_start, color);
}

// 画圆
void LCD_DrawCircle(u16 x, u16 y, u8 r, u16 color)
{
	int a, b;
	
	a = 0;
	b = r;
	while (a <= b)
	{
		LCD_DrawPoint(x - b, y - a, color);
		LCD_DrawPoint(x - b, y + a, color);
		LCD_DrawPoint(x + b, y - a, color);
		LCD_DrawPoint(x + b, y + a, color);
		LCD_DrawPoint(x + a, y - b, color);
		LCD_DrawPoint(x - a, y - b, color);
		LCD_DrawPoint(x + a, y + b, color);
		LCD_DrawPoint(x - a, y + b, color);
		a++;
		if ((a * a + b * b) > (r * r))
		{
			b--;
		}
	}
}

// 显示图片
void LCD_ShowPicture(u16 x, u16 y, u16 width, u16 height, u8 *data)
{
	LCD_Address_Set(x, y, x + width - 1, y + height - 1);
	printf("width %d height %d\n", width, height);
	LCD_WriteData(data, width * height * 2);
}
